package com.soft.base.spring.request.adapter;

import com.soft.base.spring.request.annotation.*;
import com.xiaoleilu.hutool.bean.BeanUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
/**
 * class
 *
 * @author user
 * @date 2020/06/05
 */
@ControllerAdvice
public class FieldFilterRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.getParameterAnnotation(RequestFieldFilter.class) != null
                && BeanUtil.isBean(methodParameter.getParameterType());
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        processBean(body);
        return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
    }

    private void processBean(Object bean) {
        if (null == bean) {
            return;
        }
        Class<?> aClass = bean.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        try {
            for (Field declaredField : declaredFields) {
                PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(aClass, declaredField.getName());
                Object value = propertyDescriptor.getReadMethod().invoke(bean);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                if (null == writeMethod) {
                    continue;
                }
                if (null != value && BeanUtil.isBean(value.getClass())) {
                    processBean(value);
                    continue;
                } else if (value instanceof Iterable) {
                    for (Object o : ((Iterable) value)) {
                        processBean(o);
                    }
                    continue;
                }
                Class<?> propertyType = propertyDescriptor.getPropertyType();
                for (Annotation annotation : declaredField.getAnnotations()) {
                    if (annotation instanceof FieldFilterTrim) {
                        if (null == value) {
                            continue;
                        }
                        if (value instanceof String) {
                            if (StrUtil.isNotEmpty((String) value)) {
                                value = ((String) value).trim();
                                writeMethod.invoke(bean, value);
                            }
                        }
                    } else if (annotation instanceof FieldFilterNullToEmpty) {
                        if (null == value) {
                            value = "";
                            writeMethod.invoke(bean, value);
                        }
                    } else if (annotation instanceof FieldFilterNullToZero) {
                        if (null == value) {
                            if (propertyType.isAssignableFrom(Long.class)) {
                                value = 0L;
                            } else if (propertyType.isAssignableFrom(Integer.class)) {
                                value = 0;
                            } else if (propertyType.isAssignableFrom(Byte.class)) {
                                value = (byte) 0;
                            } else if (propertyType.isAssignableFrom(Double.class)) {
                                value = .0;
                            } else if (propertyType.isAssignableFrom(Float.class)) {
                                value = .0;
                            }
                            if (null != value) {
                                writeMethod.invoke(bean, value);
                            }
                        }
                    } else if (annotation instanceof FieldFilterNullToFalse) {
                        if (null == value) {
                            value = Boolean.FALSE;
                            writeMethod.invoke(bean, value);
                        }
                    }
                }
            }
        } catch (Exception e) {
        }
    }

}